package pl.agh.convexhulltutor.algorithms;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import pl.agh.convexhulltutor.gui.DrawPanel;
import pl.agh.convexhulltutor.structures.Line;
import pl.agh.convexhulltutor.structures.Point;

public class JarvisAlgorithm extends Algorithm {
	private DrawPanel drawPanel;
	private List<Point> convexHull = new ArrayList<Point>();

	public JarvisAlgorithm(DrawPanel drawPanel) {
		super(drawPanel);
		this.drawPanel = drawPanel;
	}

	private void calculateConvexHull(List<Point> points, List<Line> lines) {
		Point pointOnHull = Collections.min(points);
		Point endpoint;
		lines.add(new Line(new Point(pointOnHull.getX(), 0), new Point(
				pointOnHull.getX(), drawPanel.getHeight() - 1)));
		pointOnHull.setColor(Point.CONVEX_HULL_COLOR);
		int i = 0;
		do {
			convexHull.add(pointOnHull);
			endpoint = points.get(0);
			for (int j = 1; j < points.size(); j++) {
				if (endpoint == pointOnHull
						|| getDeterminantSign(convexHull.get(i), endpoint,
								points.get(j)) == 1) {
					endpoint = points.get(j);
				}
			}
			i++;
			pointOnHull = endpoint;
		} while (endpoint != convexHull.get(0));
	}

	@Override
	public void execute(List<Point> points, List<Line> lines) {
		if (currentStep == 1) {
			calculateConvexHull(points, lines);
		} else if (currentStep - 1 < convexHull.size()) {
			Point oldVertex = null;
			Point newVertex = null;
			for (Point point : points) {
				if (point.compareTo(convexHull.get(currentStep - 2)) == 0) {
					oldVertex = point;
				}
				if (point.compareTo(convexHull.get(currentStep - 1)) == 0) {
					newVertex = point;
				}
			}
			lines.add(new Line(oldVertex, newVertex, Line.CONVEX_HULL_COLOR));
			newVertex.setColor(Point.CONVEX_HULL_COLOR);
		} else {
			Point oldVertex = null;
			Point newVertex = null;
			for (Point point : points) {
				if (point.compareTo(convexHull.get(currentStep - 2)) == 0) {
					oldVertex = point;
				}
				if (point.compareTo(convexHull.get(0)) == 0) {
					newVertex = point;
				}
			}
			lines.add(new Line(oldVertex, newVertex, Line.CONVEX_HULL_COLOR));
			maxStep = currentStep;
			for (Point point : points) {
				if (point.getColor() != Point.CONVEX_HULL_COLOR) {
					point.setColor(Point.NON_CONVEX_HULL_COLOR);
				}
			}
		}
	}
}
